/**   
 * @{#} MvelEnv.java Create on 2013-4-14 下午4:47:49   
 *   
 * Copyright (c) 2012 by Baidu.   
 */
package objtable.core;

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

/**
 * @author <a href="mailto:zhangbo07@baidu.com">zhangbo07</a>
 * @version 1.0
 */

public class ScriptEnv {
	// 函数对象注册在这里
	private static HashMap<String, Object> hm_computeObj;
	// 函数描述注册在这里
	private static HashMap<String, ComputeFuncDesc> hm_funcs;
	// 已经编译过的表达式
	private static HashMap<String, CompiledScript> hm_seriExpress;
	private static ScriptEngine engine;

	static {
		hm_computeObj = new HashMap<String, Object>();
		hm_funcs = new HashMap<String, ComputeFuncDesc>();
		hm_seriExpress = new HashMap<String, CompiledScript>();
		ScriptEngineManager sem = new ScriptEngineManager();
		engine = sem.getEngineByName("Groovy");

		// 注册默认的方法
		ScriptUtil su = new ScriptUtil();
		innerRegComputeFuc("println", su);
	}

	private ScriptEnv() {
	}

	// 注册的时候只有函数名，内部生成（对象名.函数名<-->函数名)的映射关系
	public static void regComputeFunc(String funcname, Object obj) {
		ReserveWord.checkWord(funcname);
		innerRegComputeFuc(funcname, obj);
	}

	private static void innerRegComputeFuc(String funcname, Object obj) {
		ComputeFuncDesc cfd = new ComputeFuncDesc();
		cfd.objName = "func" + IntKeyGen.nextInt();
		cfd.funcName = funcname;
		hm_computeObj.put(cfd.objName, obj);
		hm_funcs.put(funcname, cfd);
	}

	// 执行复杂的表达式计算
	public static Object execute(String exp, HashMap<String, Object> computeObj) {
		Object result = null;
		try {
			// 替换函数方法
			String express = replaceExpressFunc(exp);
			if (!hm_seriExpress.containsKey(express)) {
				hm_seriExpress.put(express, compileExpression(express));
			}
			CompiledScript cs = hm_seriExpress.get(express);
			Bindings b = new SimpleBindings(computeObj);
			result = cs.eval(b);
		} catch (ScriptException e1) {
			e1.printStackTrace();
		}
		return result;
	}

	private static CompiledScript compileExpression(String express)
			throws ScriptException {
		CompiledScript c = ((Compilable) engine).compile(express);
		return c;
	}

	private static String replaceExpressFunc(String express) {
		Set<String> keys = hm_funcs.keySet();
		for (String funcname : keys) {
			// 注意需要带上右括号进行替换
			express = express.replaceAll(funcname + "\\(",
					hm_funcs.get(funcname).getFuncStr() + "\\(");
		}
		return express;
	}

	@SuppressWarnings("unchecked")
	// 克隆对象内部包含已注册的计算函数
	public static HashMap<String, Object> cloneComputeObj() {
		return (HashMap<String, Object>) hm_computeObj.clone();
	}

	private static class ComputeFuncDesc {
		String objName;
		String funcName;

		public String getFuncStr() {
			return objName + "." + funcName;
		}
	}

	public final static String replaceFieldsWithPrefix(String express,
			String[] fields, String prefix) {
		Arrays.sort(fields, new Comparator<String>() {
			public int compare(String o1, String o2) {
				return -o1.compareTo(o2);
			}
		});

		for (String field : fields) {
			Pattern pat = Pattern.compile("([^.\\w]|^)(" + field
					+ ")([^(\\w]|$)");
			Matcher m = pat.matcher(express);
			while (m.find()) {
				express = m.replaceFirst("$1" + prefix + field + "$3");
				m = pat.matcher(express);
			}
		}
		return express;
	}

	static class ScriptUtil {
		public void println(Object o) {
			System.out.println(o);
		}
	}
}
